//SPDX-FileCopyrightText: Copyright 2022-2024 深圳市同心圆网络有限公司
//SPDX-License-Identifier: GPL-3.0-only

use tauri::{
    plugin::{Plugin, Result as PluginResult},
    AppHandle, Invoke, PageLoadPayload, Runtime, Window,
};
use tokio::fs;
use tokio::io::AsyncReadExt;
use tokio::io::AsyncWriteExt;

use crate::user_api_plugin::{decrypt_string, encrypt_string, get_user_id};

#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq)]
pub struct UserServerInfo {
    pub id: String,
    pub name: String,
    pub server_type: u32, //对应minapp APP_TYPE
    pub server_info: String,
    pub project_id: Option<String>, //关联项目
}

async fn load_server_list<R: Runtime>(
    app_handle: AppHandle<R>,
) -> Result<Vec<UserServerInfo>, String> {
    let user_dir = crate::get_user_dir();
    if user_dir.is_none() {
        return Err("miss user dir".into());
    }
    let user_id = get_user_id(app_handle.clone()).await;
    if user_id == "" {
        return Err("must login".into());
    }
    let mut file_path = std::path::PathBuf::from(user_dir.unwrap());
    file_path.push(user_id);
    file_path.push("my_server.json");

    if !file_path.exists() {
        return Ok(Vec::new());
    }

    let f = fs::File::open(file_path).await;
    if f.is_err() {
        return Err(f.err().unwrap().to_string());
    }
    let mut f = f.unwrap();
    let mut data = Vec::new();
    let result = f.read_to_end(&mut data).await;
    if result.is_err() {
        return Err(result.err().unwrap().to_string());
    }
    let json_str = String::from_utf8(data);
    if json_str.is_err() {
        return Err(json_str.err().unwrap().to_string());
    }
    let json_str = json_str.unwrap();
    let server_list = serde_json::from_str(&json_str);
    if server_list.is_err() {
        return Err(server_list.err().unwrap().to_string());
    }
    let mut server_list: Vec<UserServerInfo> = server_list.unwrap();
    for server in &mut server_list {
        let info = decrypt_string(app_handle.clone(), &server.server_info, false).await;
        if info.is_err() {
            return Err(info.err().unwrap().to_string());
        }
        server.server_info = info.unwrap();
    }
    return Ok(server_list);
}

async fn save_server_list<R: Runtime>(
    app_handle: AppHandle<R>,
    server_list: Vec<UserServerInfo>,
) -> Result<(), String> {
    let user_dir = crate::get_user_dir();
    if user_dir.is_none() {
        return Err("miss user dir".into());
    }
    let user_id = get_user_id(app_handle.clone()).await;
    if user_id == "" {
        return Err("must login".into());
    }
    let mut file_path = std::path::PathBuf::from(user_dir.unwrap());
    file_path.push(user_id);
    file_path.push("my_server.json");

    let mut new_server_list = server_list.clone();
    for server in &mut new_server_list {
        let info = encrypt_string(app_handle.clone(), &server.server_info, false).await;
        if info.is_err() {
            return Err(info.err().unwrap().to_string());
        }
        server.server_info = info.unwrap();
    }

    let json_str = serde_json::to_string(&new_server_list);
    if json_str.is_err() {
        return Err(json_str.err().unwrap().to_string());
    }
    let json_str = json_str.unwrap();

    let f = fs::File::create(file_path).await;
    if f.is_err() {
        return Err(f.err().unwrap().to_string());
    }
    let mut f = f.unwrap();
    let result = f.write_all(json_str.as_bytes()).await;
    if result.is_err() {
        return Err(result.err().unwrap().to_string());
    }

    return Ok(());
}

#[tauri::command]
async fn add_server<R: Runtime>(
    app_handle: AppHandle<R>,
    server: UserServerInfo,
) -> Result<(), String> {
    let tmp_list = load_server_list(app_handle.clone()).await;
    if tmp_list.is_err() {
        return Err(tmp_list.err().unwrap());
    }
    let tmp_list = tmp_list.unwrap();
    for cmp_server in &tmp_list {
        if cmp_server.id == server.id {
            return Ok(());
        }
    }

    let mut server_list = vec![server];
    server_list.extend(tmp_list);
    return save_server_list(app_handle, server_list).await;
}

#[tauri::command]
async fn update_server<R: Runtime>(
    app_handle: AppHandle<R>,
    server: UserServerInfo,
) -> Result<(), String> {
    let tmp_list = load_server_list(app_handle.clone()).await;
    if tmp_list.is_err() {
        return Err(tmp_list.err().unwrap());
    }
    let tmp_list = tmp_list.unwrap();
    let mut new_server_list = Vec::new();
    for cmp_server in &tmp_list {
        let server_id = server.id.clone();
        if cmp_server.id == server_id {
            new_server_list.push(server.clone());
        } else {
            new_server_list.push(cmp_server.clone());
        }
    }

    return save_server_list(app_handle, new_server_list).await;
}

#[tauri::command]
async fn remove_server<R: Runtime>(app_handle: AppHandle<R>, id: String) -> Result<(), String> {
    let tmp_list = load_server_list(app_handle.clone()).await;
    if tmp_list.is_err() {
        return Err(tmp_list.err().unwrap());
    }
    let tmp_list = tmp_list.unwrap();
    let mut new_server_list = Vec::new();
    for cmp_server in &tmp_list {
        if cmp_server.id != id {
            new_server_list.push(cmp_server.clone());
        }
    }

    return save_server_list(app_handle, new_server_list).await;
}

#[tauri::command]
async fn list_server<R: Runtime>(app_handle: AppHandle<R>) -> Result<Vec<UserServerInfo>, String> {
    return load_server_list(app_handle).await;
}

pub struct UserServerApiPlugin<R: Runtime> {
    invoke_handler: Box<dyn Fn(Invoke<R>) + Send + Sync + 'static>,
}

impl<R: Runtime> UserServerApiPlugin<R> {
    pub fn new() -> Self {
        Self {
            invoke_handler: Box::new(tauri::generate_handler![
                add_server,
                update_server,
                remove_server,
                list_server,
            ]),
        }
    }
}

impl<R: Runtime> Plugin<R> for UserServerApiPlugin<R> {
    fn name(&self) -> &'static str {
        "user_server_api"
    }
    fn initialization_script(&self) -> Option<String> {
        None
    }

    fn initialize(&mut self, _app: &AppHandle<R>, _config: serde_json::Value) -> PluginResult<()> {
        Ok(())
    }

    fn created(&mut self, _window: Window<R>) {}

    fn on_page_load(&mut self, _window: Window<R>, _payload: PageLoadPayload) {}

    fn extend_api(&mut self, message: Invoke<R>) {
        (self.invoke_handler)(message)
    }
}
